package report

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/toolkits/file"
	"github.com/xuri/excelize/v2"
	"gopkg.in/yaml.v2"
)

type IReport interface {
	GetReport() *Report
}

type Report struct {
	CreatedAt   string        `json:"createdAt"`
	CPU         CPUInfo       `json:"cpus"`
	Memory      MemoryInfo    `json:"memory"`
	DiskSummary DiskSummary   `json:"diskSummary"`
	Disks       []DiskInfo    `json:"disks"`
	IpAddresses []string      `json:"ipAddresses"`
	Networks    []NetworkInfo `json:"networks"`
	Host        HostInfo      `json:"os"`
	Load        LoadInfo      `json:"load"`
}

func NewReport() *Report {
	return &Report{
		CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
	}
}

func (r *Report) Fetch() error {

	r.CPU = FetchCpuInfo()
	r.Memory = FetchMemoryInfo()
	r.Disks = FetchDiskInfo()
	r.DiskSummary = FetchDiskSummary(r.Disks)

	r.Networks = FetchNetworkInfo()
	r.IpAddresses = FetchIpAddresses()
	r.Host = FetchOSInfo()
	r.Load = FetchLoadInfo()

	return nil
}

func (r *Report) Show() {
	out, err := yaml.Marshal(r)
	if err != nil {
		return
	}

	fmt.Printf("report : %v\n", string(out))

}

func (r *Report) Save() error {

	resultDir := filepath.Join(file.SelfDir(), "result")
	if !file.IsExist(resultDir) {
		if err := os.MkdirAll(resultDir, 0755); err != nil {
			return err
		}
	}

	fileName := fmt.Sprintf("report_%s_%s.xlsx", r.Host.Hostname, time.Now().Format("20060102"))
	filePath := filepath.Join(resultDir, fileName)
	if !file.IsExist(filePath) {
		if err := r.NewFile(filePath); err != nil {
			return err
		}
	}

	return r.AppendData()
}

func (r *Report) NewFile(name string) error {
	fmt.Println("NewFile: ", name)
	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	// 设置summary sheet
	f.SetSheetName("Sheet1", "Summary")
	index, err := f.GetSheetIndex("Summary")
	if err != nil {
		fmt.Println(err)
		return err
	}
	f.SetActiveSheet(index)
	f.SetCellValue("Summary", "A1", "主机名称")
	f.SetCellValue("Summary", "B1", r.Host.Hostname)
	f.SetCellValue("Summary", "A2", "CPU")
	f.SetCellValue("Summary", "B2", r.CPU.Count)
	f.SetCellValue("Summary", "A3", "创建时间")
	f.SetCellValue("Summary", "B3", r.CreatedAt)

	// 自适应列宽
	f.SetColWidth("Summary", "A", "A", 16)
	f.SetColWidth("Summary", "B", "B", 20)

	// 创建data sheet
	index, err = f.NewSheet("data")
	if err != nil {
		fmt.Println(err)
		return err
	}
	// 设置表头
	f.SetActiveSheet(index)
	headers := []string{"主机名称", "采集时间", "CPU核心数", "CPU使用率"}

	// 主机信息
	headers = append(headers, "主机名称", "运行时间", "运行时长", "启动时间戳", "启动时间", "进程数", "操作系统", "平台", "平台家族", "平台版本", "内核版本", "内核架构", "虚拟化系统", "虚拟化角色", "主机ID")

	// cpu信息
	for i, _ := range r.CPU.Info {
		headers = append(headers, fmt.Sprintf("CPU %d", i))
	}
	// 内存信息
	headers = append(headers, "内存总量", "内存可用", "内存使用", "内存空闲", "内存使用率")
	// 磁盘摘要
	headers = append(headers, "磁盘总量", "磁盘总使用", "磁盘总空闲", "磁盘总使用率")
	// 磁盘信息
	for i, _ := range r.Disks {
		headers = append(headers, fmt.Sprintf("磁盘%d总量", i))
		headers = append(headers, fmt.Sprintf("磁盘%d使用", i))
		headers = append(headers, fmt.Sprintf("磁盘%d空闲", i))
		headers = append(headers, fmt.Sprintf("磁盘%d使用率", i))
	}
	// 网络IP地址
	headers = append(headers, "IP地址")
	// 网络信息
	for i, _ := range r.Networks {
		headers = append(headers, fmt.Sprintf("网络%d接口", i))
		headers = append(headers, fmt.Sprintf("网络%dIP", i))
		headers = append(headers, fmt.Sprintf("网络%dMAC", i))
		headers = append(headers, fmt.Sprintf("网络%d收包", i))
		headers = append(headers, fmt.Sprintf("网络%d发包", i))
		headers = append(headers, fmt.Sprintf("网络%d收字节", i))
		headers = append(headers, fmt.Sprintf("网络%d发字节", i))
	}
	// 负载
	headers = append(headers, "1分钟负载", "5分钟负载", "15分钟负载", "总进程数", "已创建进程数", "运行进程数", "阻塞进程数", "上下文切换次数")

	f.SetSheetRow("data", "A1", &headers)
	// 创建一个新的样式并设置字体加粗
	styleID, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Bold: true,
		},
	})
	if err != nil {
		fmt.Println("Error creating style:", err)
		return err
	}
	f.SetRowStyle("data", 1, len(headers), styleID)

	// 设置文件属性
	f.SetDocProps(&excelize.DocProperties{
		Title:          "主机监控报告",
		Subject:        "主机监控报告",
		Creator:        "hongsheng",
		Version:        "1.0",
		LastModifiedBy: "probe",
	})

	// 根据指定路径保存文件
	if err := f.SaveAs(name); err != nil {
		fmt.Println(err)
		return err
	}

	return nil
}

func (r *Report) AppendData() error {
	// 读取文件
	resultDir := filepath.Join(file.SelfDir(), "result")
	fileName := fmt.Sprintf("report_%s_%s.xlsx", r.Host.Hostname, time.Now().Format("20060102"))
	filePath := filepath.Join(resultDir, fileName)
	f, err := excelize.OpenFile(filePath)
	if err != nil {
		fmt.Println(err)
		return err
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	// 获取工作表
	sheetName := "data"
	index, err := f.GetSheetIndex(sheetName)
	if err != nil {
		fmt.Println(err)
		return err
	}
	if index == 0 {
		fmt.Println("sheet not found")
		return fmt.Errorf("sheet not found")
	}
	f.SetActiveSheet(index)

	// 获取行数
	rows, err := f.GetRows(sheetName)
	if err != nil {
		fmt.Println(err)
		return err
	}

	// 获取插入的行号
	lastRow := len(rows) + 1

	data := []string{
		r.Host.Hostname,
		r.CreatedAt,
		fmt.Sprintf("%d", r.CPU.Count),
		fmt.Sprintf("%.2f", r.CPU.Precent),
		r.Host.Hostname,
		fmt.Sprintf("%d", r.Host.Uptime),
		r.Host.UptimeHuman,
		fmt.Sprintf("%d", r.Host.BootTime),
		r.Host.BootTimeHuman,
		fmt.Sprintf("%d", r.Host.Procs),
		r.Host.OS,
		r.Host.Platform,
		r.Host.PlatformFamily,
		r.Host.PlatformVersion,
		r.Host.KernelVersion,
		r.Host.KernelArch,
		r.Host.VirtualizationSystem,
		r.Host.VirtualizationRole,
		r.Host.HostID,
	}

	// cpu信息
	for _, v := range r.CPU.Info {
		cinfo, err := yaml.Marshal(v)
		if err != nil {
			return err
		}
		data = append(data, string(cinfo))
	}
	// 内存信息
	data = append(data, fmt.Sprintf("%d", r.Memory.Total))
	data = append(data, fmt.Sprintf("%d", r.Memory.Available))
	data = append(data, fmt.Sprintf("%d", r.Memory.Used))
	data = append(data, fmt.Sprintf("%d", r.Memory.Free))
	data = append(data, fmt.Sprintf("%.2f", r.Memory.UsedPercent))

	// 磁盘摘要
	data = append(data, fmt.Sprintf("%d", r.DiskSummary.Size))
	data = append(data, fmt.Sprintf("%d", r.DiskSummary.Used))
	data = append(data, fmt.Sprintf("%d", r.DiskSummary.Free))
	data = append(data, fmt.Sprintf("%.2f", r.DiskSummary.UsedPercent))

	// 磁盘信息
	for _, v := range r.Disks {
		data = append(data, fmt.Sprintf("%d", v.Total))
		data = append(data, fmt.Sprintf("%d", v.Used))
		data = append(data, fmt.Sprintf("%d", v.Free))
		data = append(data, fmt.Sprintf("%.2f", v.UsedPercent))
	}

	// 网络IP地址
	ips := strings.Join(r.IpAddresses, ",")
	data = append(data, ips)

	// 网络信息
	for _, v := range r.Networks {
		data = append(data, v.Name)
		data = append(data, fmt.Sprintf("%v", v.Addrs))
		data = append(data, v.HardwareAddr)
		data = append(data, fmt.Sprintf("%d", v.PacketsRecv))
		data = append(data, fmt.Sprintf("%d", v.PacketsSent))
		data = append(data, fmt.Sprintf("%d", v.BytesRecv))
		data = append(data, fmt.Sprintf("%d", v.BytesSent))
	}
	// 负载 headers = append(headers, "1分钟负载", "5分钟负载", "15分钟负载", "总进程数", "已创建进程数", "运行进程数", "阻塞进程数", "上下文切换次数")
	data = append(data, fmt.Sprintf("%.2f", r.Load.Avg1))
	data = append(data, fmt.Sprintf("%.2f", r.Load.Avg5))
	data = append(data, fmt.Sprintf("%.2f", r.Load.Avg15))
	data = append(data, fmt.Sprintf("%d", r.Load.ProcsTotal))
	data = append(data, fmt.Sprintf("%d", r.Load.ProcsCreated))
	data = append(data, fmt.Sprintf("%d", r.Load.ProcsRunning))
	data = append(data, fmt.Sprintf("%d", r.Load.ProcsBlocked))
	data = append(data, fmt.Sprintf("%d", r.Load.Ctxt))

	// fmt.Printf("data: %v\n", data)
	// fmt.Printf("lastRow: %v\n", lastRow)
	// 写入数据
	f.SetSheetRow(sheetName, fmt.Sprintf("A%d", lastRow), &data)

	if err := f.SaveAs(filePath); err != nil {
		fmt.Println(err)
		return err
	}

	return nil
}
